package co.edu.unal.bioingenium.kbmed.retrieval.text.process;

import co.edu.unal.bioingenium.kbmed.features.CollectionFeatures;
import co.edu.unal.bioingenium.kbmed.text.representation.vo.Corpus;
import co.edu.unal.bioingenium.kbmed.retrieval.vo.QueryDocument;
import co.edu.unal.bioingenium.kbmed.text.index.structures.InvertedIndexIntToInt;
import co.edu.unal.bioingenium.kbmed.retrieval.vo.RelevantDocument;
import co.edu.unal.bioingenium.kbmed.retrieval.text.similarity.Cosine;
import gnu.trove.map.TObjectIntMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 *
 * @author Alejandro Riveros Cruz
 */
public class RankByWords {

    private Cosine cosine;

    /**
     * 
     */
    public RankByWords() {
        cosine = new Cosine();
    }

    /**
     * 
     * @param query 
     * @param corpus 
     * @param indexByDocument 
     * @param features 
     * @return
     */
    public List<RelevantDocument> retrieveByWords(QueryDocument query, Corpus corpus, InvertedIndexIntToInt indexByDocument, CollectionFeatures features) {
        List<RelevantDocument> results = new ArrayList<RelevantDocument>();
        //Build the candidate document subset using inverted index
        Set<Integer> candidateDocuments = buildCandidateDocumentSet(query, corpus, indexByDocument);
        //Evaluate  the document subset using the choosed similarity function
        results = evaluateCandidatesByWords(query, candidateDocuments, corpus, features);
        return results;
    }

    /**
     * 
     * @param queryDocument
     * @param corpus 
     * @param wordByDocument 
     * @return
     */
    private Set<Integer> buildCandidateDocumentSet(QueryDocument queryDocument, Corpus corpus, InvertedIndexIntToInt wordByDocument) {
        TObjectIntMap<String> invertedWordList = corpus.getInvertedSortedWordList();
        Set<Integer> candidateSet = new HashSet<Integer>();
        for (String word : queryDocument.getWordList().keySet()) {
            candidateSet.addAll(wordByDocument.getElement(invertedWordList.get(word)));
        }
        return candidateSet;
    }

    /**
     * 
     * @param queryDocument 
     * @param candidateSet
     * @param corpus 
     * @param collectionFeatures 
     * @return
     */
    private List<RelevantDocument> evaluateCandidatesByWords(QueryDocument queryDocument, Set<Integer> candidateSet, Corpus corpus, CollectionFeatures collectionFeatures) {
        List<RelevantDocument> scoredCandidates = new ArrayList<RelevantDocument>();
        float score;
        for (Integer documentId : candidateSet) {
            score = cosine.getValue(collectionFeatures.getFeatureVector(documentId), queryDocument.getFeatureVector());
            scoredCandidates.add(new RelevantDocument(corpus.getSortedDocumentList().get(documentId), score));
        }
        Collections.sort(scoredCandidates);
        return scoredCandidates;
    }
}
